#pragma once

#include <memory>
#include "Node2D.h"
#include "lib3d/hard/Manager.h"
#include "HardwareDependentObject.h"
#include <math/vector2.h>
#include <math/Rect.h>
#include <Object2D.h>
#include <CompilerFeatures.h>

namespace liba {
namespace lib3d {

namespace material
{
	class TextureFrame;
}

namespace node {

class Sprite
	: public Node2D, private HardwareDependentObject<hard::Manager, hard::VertexBuffer>
{
	NODE_DEFINITION(Sprite)
public:
	Sprite(const Atom& name, Node* parent);
	Sprite(const Sprite& rhs);
	virtual ~Sprite();

	virtual Node* Clone() LIBA_OVERRIDE;

	static const Atom node_name;
	static const Atom transparency_name;
	static const Atom frame_index_name;
	static const Atom src_name;
	static const Atom frame_name;
	static const Atom color_name;

	virtual bool on_attribute(xml::Provider * prov, const std::string & name, const std::string & value) LIBA_OVERRIDE;
	virtual bool on_end_node(xml::Provider * prov) LIBA_OVERRIDE;

	virtual void RenderToList( hard::Hardware * hardware, hard::RenderList * render_list ) LIBA_OVERRIDE;
	void SetColor(liba::Color color);
	void SetTransparency(float _transparency);

	int GetWidth();
	int GetHeight();
	virtual math::Rect<float> GetLocalBounds() LIBA_OVERRIDE;

	void SetAnchorPoint(const math::Vector2 <float> & point);
	const math::Vector2 <float>& GetAnchorPoint() const { return anchorPoint; }

	void SetTexture(const filesystem::String &fileName);
	void SetTexture(hard::Hardware * hardware, hard::Texture * texture);
	void SetAtlasTexture(const filesystem::String &fileName, const std::string &frameName);
	void SetAtlasTexture(const filesystem::String &fileName, int frameIndex);
	void SetFragment(const math::Rect<float>& value);

	void SetTextureFilter(bool state);
	bool GetTextureFilter() const { return filterTexture; }

	void SetTile(const math::Vector2 <float> &tile);
	void SetTileOffset(const math::Vector2 <float> &offset);

	const math::Vector2 <float>& GetTile() const { return tile; }
	const math::Vector2 <float>& GetTileOffset() const { return tileOffset; }

	material::TextureFrame* GetTexture() const { return texture.get(); }
	virtual void CreateProxy(ProxyVisitor * proxyVisitor) LIBA_OVERRIDE;

	filesystem::String GetTextureName() const;
	filesystem::String GetAtlasTextureName() const;
	std::string GetAtlasTextureFrame() const;
protected:
	virtual void on_save_attributes(xml::SaverBase * saver) const LIBA_OVERRIDE;
private:
	virtual void on_add_hardware(hard::Manager::hardware_type* ha);

	void fill_vb(hard::VertexBuffer* vb);

	math::Vector2 <float> GetLeftBottom();

	void SetFrameIndex(double value);
	void SetSource(const filesystem::String &value);
	void SetFrame(const std::wstring &value);

private:
	std::auto_ptr <material::TextureFrame> texture;
	std::auto_ptr <material::TextureFrame> oldTexture;
	
	math::Vector2 <float> anchorPoint;
	math::Rect<float> fragment;
	bool absoluteFragment;
	bool recreateVb;

	bool filterTexture;
	properties::DependencyProperty<double> transparency;
	properties::VirtualDependencyProperty<double> frameIndex;
	properties::VirtualDependencyProperty<filesystem::String> source;
	properties::VirtualDependencyProperty<std::wstring> frame;
	properties::DependencyProperty<Color> color;

	math::Vector2 <float> tile;
	math::Vector2 <float> tileOffset;

private:
	struct AtlasInfo
	{
		filesystem::String atlasName;
		std::string frameName;
	} atlasInfo;

	filesystem::String texFileName;
	bool wrap;
};

} // namespace node
} // namespace lib3d
} // namespace liba